use std::collections::HashMap;
use std::sync::Arc;
use std::sync::OnceLock;
use std::sync::RwLock;

use crate::session::session::Session;

#[derive(Clone, Debug)]
pub struct SessionManager {
    timeout: u64,
    sessions: Arc<RwLock<HashMap<String, Session>>>, //hashmap线程不安全, Arc 允许多线程同时访问, 但需要使用RwLock来保证线程安全
}

const DEFAULT_TIMEOUT: u64 = 1800; //默认时间为1800秒
const DEFAULT_SESSION_COUNT: usize = 1;

static SESSION_MANAGER: OnceLock<SessionManager> = OnceLock::new();

impl SessionManager {
    pub fn init(timeout: Option<u64>) -> Result<(), Box<dyn std::error::Error>> {
        let timeout = timeout.unwrap_or(DEFAULT_TIMEOUT);
        let manager = SessionManager {
            timeout,
            sessions: Arc::new(RwLock::new(HashMap::with_capacity(DEFAULT_SESSION_COUNT))),
        };

        SESSION_MANAGER
            .set(manager)
            .map_err(|_| "Already initialized".into())
    }

    pub fn get() -> &'static SessionManager {
        SESSION_MANAGER
            .get()
            .expect("SessionManager not initialized")
    }

    pub fn add_session(
        &self,
        id: String,
        session: Session,
    ) -> Result<(), Box<dyn std::error::Error>> {
        let mut sessions = self.sessions.write().map_err(|e| {
            Box::new(std::io::Error::new(
                std::io::ErrorKind::Other,
                format!("Failed to acquire write lock: {}", e),
            ))
        })?;

        sessions.insert(id, session);
        Ok(())
    }

    pub fn remove_session(&self, id: &str) -> Result<(), Box<dyn std::error::Error>> {
        let mut sessions = self.sessions.write().map_err(|e| {
            Box::new(std::io::Error::new(
                std::io::ErrorKind::Other,
                format!("Failed to acquire write lock: {}", e),
            ))
        })?;

        sessions.remove(id);
        Ok(())
    }

    pub fn is_session_exist(&self, id: &str) -> bool {
        self.sessions.read().map_or(false, |s| s.contains_key(id))
    }

    pub fn is_expired(&self, id: &str) -> bool {
        self.sessions
            .read()
            .unwrap()
            .get(id)
            .map_or(false, |session| session.is_expired(self.timeout))
    }
}
